import * as React from 'react';
import { MeshMessage } from '../MeshMessage/MeshMessage';
import { OperationalInformation } from '../OperationalInformation/OperationalInformation';
import './EditorContent.scss';
import * as THREE from 'three';
import { Vector3 } from 'three';
import {
  EVENT_CHANGE_TRANSFORM_CONTROLS,
  EditorModels,
  EVENT_SELECT_MESH,
  EVENT_DESELECT_MESH,
} from '../../ts/EditorModels';
import { throttle } from '@/utils/Utils';
import { IEditorAssets } from '../OperationalInformation/data';
export interface ISelectMesh {
  /** 选中可以操作的那个mesh */
  mesh: THREE.Object3D;
  /** 用于触发更新 */
  visit: boolean;
}

/** 拖拽的类型 */
export const EVENT_DRAG_TYPE = 'EVENT_DRAG_TYPE';
/** 拖拽的类型 */
export enum EnumDragType {
  /** 模型 */
  MODEL_DRAG = 'MODEL_DRAG',
  /** 材质 */
  MATERIAL_DRAG = 'MATERIAL_DRAG',
  /** 贴图 */
  TEXTURE_MAP_DRAG = 'TEXTURE_MAP_DRAG',
  /** 灯光 */
  LIGHT_DRAG = 'LIGHT_DRAG',
}

let editorRefTop: number; // editor canvas 的上偏移量
let editorRefLeft: number; // editor canvas 的左偏移量
let editorScene: EditorModels;
/** 当前拖拽的类型 */
let currentDragType: EnumDragType;

export interface IEditorContentProps {
  onchange: (editorScene: EditorModels) => void;
  headerHeight: number;
}
let nullObject3D = new THREE.Object3D();
export function EditorContent(props: IEditorContentProps) {
  const editorRef = React.useRef<HTMLDivElement>(null);
  const editorContentPageRef = React.useRef<HTMLDivElement>(null);
  let [selectMesh, setSelectMesh] = React.useState<ISelectMesh>({
    mesh: nullObject3D,
    visit: false,
  });

  React.useEffect(() => {
    if (editorRef && editorRef.current) {
      editorScene = new EditorModels({
        renderParams: {
          width: editorRef.current!.clientWidth,
          height: editorRef.current!.clientHeight,
          renderContainer: editorRef.current,
          devicePixelRatio: window.devicePixelRatio,
        },
        cameraParams: {
          fov: 45,
          near: 0.1,
          far: 1000,
          cameraPosition: new Vector3(-0.77, 13.5, 19.12),
        },
        isOrbitControls: true,
        isTransformControls: true,
        isViewHelper: true,
      });
      props.onchange(editorScene);
      let { top, left } = editorRef.current?.getBoundingClientRect();
      editorRefTop = top;
      editorRefLeft = left;

      editorScene.orbitControls.enablePan = false;
      editorScene.orbitControls.mouseButtons = {
        LEFT: THREE.MOUSE.PAN,
        MIDDLE: THREE.MOUSE.ROTATE,
        RIGHT: THREE.MOUSE.DOLLY,
      };
    }

    editorScene.$on(EVENT_SELECT_MESH, ([newSelectMesh]: [THREE.Object3D]) => {
      setSelectMesh({
        visit: true,
        mesh: newSelectMesh,
      });
    });

    editorScene.$on(EVENT_DESELECT_MESH, () => {
      setSelectMesh({
        visit: false,
        mesh: nullObject3D,
      });
    });

    editorScene.$on(EVENT_DRAG_TYPE, ([dragType]: [EnumDragType]) => {
      currentDragType = dragType;
    });

    window.addEventListener('resize', updateCamera);
    return () => {
      window.removeEventListener('resize', updateCamera);
    };
  }, []);

  React.useEffect(() => {
    if (props.headerHeight === 0) return;
    editorRefTop = editorRefTop + props.headerHeight;
    updateCamera();
  }, [props.headerHeight]);

  const updateCamera = React.useCallback(() => {
    let width = editorRef.current!.clientWidth;
    // let height = editorRef.current!.clientHeight - props.headerHeight;
    let height = editorRef.current!.clientHeight;
    let { top, left } = editorRef.current?.getBoundingClientRect()!;
    editorRefTop = top;
    editorRefLeft = left;
    editorScene.raycasterControls.setDomParams({ width, height });
    (editorScene.camera as THREE.PerspectiveCamera).aspect = width / height;
    (editorScene.camera as THREE.PerspectiveCamera).updateProjectionMatrix();
    editorScene.renderer.setSize(width, height);
  }, [props.headerHeight]);

  /** 鼠标移入canvas */
  const canvasMoveHandle = React.useCallback(
    throttle((event: React.MouseEvent<HTMLDivElement>) => {
      editorScene.updateMouse(
        new THREE.Vector2(event.clientX - editorRefLeft, event.clientY - editorRefTop),
      );
    }, 100),
    [],
  );

  /** 鼠标点击canvas */
  const canvasClickHandle = React.useCallback(
    throttle((event: React.MouseEvent<HTMLDivElement>) => {
      if (event.button !== 0) return;
      editorScene.clickMouse(
        new THREE.Vector2(event.clientX - editorRefLeft, event.clientY - editorRefTop),
      );
    }, 0),
    [],
  );

  /** 拖拽模型节流 */
  const throttleModelDrag = React.useCallback(
    throttle((event: React.MouseEvent<HTMLDivElement>) => {
      editorScene.changeCreateModelInPlanePosition(
        new THREE.Vector2(event.clientX - editorRefLeft, event.clientY - editorRefTop),
      );
    }, 10),
    [],
  );

  /** 拖拽灯光节流 */
  const throttleLightDrag = React.useCallback(
    throttle((event: React.MouseEvent<HTMLDivElement>) => {
      editorScene.changecreatLightInPlanePosition(
        new THREE.Vector2(event.clientX - editorRefLeft, event.clientY - editorRefTop),
      );
    }, 10),
    [],
  );

  /** 拖拽材质节流 */
  const throttleMaterialDrag = React.useCallback(
    throttle((event: React.MouseEvent<HTMLDivElement>) => {
      editorScene.dragChangeMeshMaterial(
        new THREE.Vector2(event.clientX - editorRefLeft, event.clientY - editorRefTop),
      );
    }, 50),
    [],
  );

  /** 修改贴图 */
  const throttleTextureMapDrag = React.useCallback(
    throttle((event: React.MouseEvent<HTMLDivElement>) => {
      editorScene.dragChangeMeshTextureMap(
        new THREE.Vector2(event.clientX - editorRefLeft, event.clientY - editorRefTop),
      );
    }, 50),
    [],
  );

  /** 正在拖拽事件 */
  const canvasDragOverHandle = (event: React.DragEvent<HTMLDivElement>) => {
    event.preventDefault();
    switch (currentDragType) {
      case EnumDragType.MODEL_DRAG:
        throttleModelDrag(event);
        break;
      case EnumDragType.MATERIAL_DRAG:
        throttleMaterialDrag(event);
        break;
      case EnumDragType.TEXTURE_MAP_DRAG:
        throttleTextureMapDrag(event);
        break;
      case EnumDragType.LIGHT_DRAG:
        throttleLightDrag(event);
        break;
    }
  };

  /** 完成拖拽事件 */
  const canvasDropHandle = (event: React.DragEvent<HTMLDivElement>) => {
    event.preventDefault();
    switch (currentDragType) {
      case EnumDragType.MODEL_DRAG:
        editorScene.completeCreateModelInPlane();
        break;
      case EnumDragType.MATERIAL_DRAG:
        editorScene.dragCompleteMeshMaterial();
        break;
      case EnumDragType.TEXTURE_MAP_DRAG:
        editorScene.dragCompleteMeshTextureMap();
        break;
      case EnumDragType.LIGHT_DRAG:
        editorScene.completeCreateLightInPlane();
        break;
    }
    editorScene.updateView();
  };

  const getCamera = () => {
    // console.log(editorScene.camera.position);
    // console.log(editorScene.camera);
    // console.log(editorScene.scene);
  };
  return (
    <div className="editorContentPage" ref={editorContentPageRef} onClick={() => getCamera()}>
      {editorScene ? (
        <OperationalInformation editorScene={editorScene}></OperationalInformation>
      ) : (
        <div className="qperationalInformationPage"></div>
      )}
      <div
        onDrop={(e) => {
          canvasDropHandle(e);
        }}
        onDragOver={(e) => {
          canvasDragOverHandle(e);
        }}
        className="canvas"
        ref={editorRef}
        onMouseDown={(e) => {
          canvasClickHandle(e);
        }}
        onMouseMove={(e) => canvasMoveHandle(e)}
      ></div>
      {editorScene && <MeshMessage selectMesh={selectMesh} editorScene={editorScene} />}
    </div>
  );
}
